package both.map.mapModel;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Cell content for the token layer
 * 
 * @author jdl
 */
public class TokenCell extends ModelCell {
	
	private List<ModelActor> actors;
	
	/**
	 * Construct a new TokenCell.
	 */
	public TokenCell()
	{
		this(false, new ArrayList<ModelActor>());
	}
	
	/**
	 * construct a new TokenCell, specifying whether it is an update or not. 
	 * Must include a list for actors.
	 */
	private TokenCell(boolean forUpdate, List<ModelActor> actors)
	{
		super(forUpdate);
		this.actors = actors;
	}
	
	/**
	 * add a new actor to the cell
	 * @param actor the actor to be added
	 * @return true if successful, false if failed
	 * TODO: add checks for whether the given actor can be 
	 * 	added to the cell, and return a result of the attempt. 
	 * TODO: provide feedback about why it fails
	 */
	public boolean addActor(ModelActor actor)
	{
		if (!isPartOfUpdate() && !containsActor(actor)) {
			actors.add(actor);
			flagForUpdate();
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * remove an actor from the cell
	 * @param actor the actor to be removed
	 * @return true if successful, false if failed
	 * TODO: provide different feedback for different reasons for failure (i.e. part of update, actor
	 * not present.
	 */
	public boolean removeActor(ModelActor actor)
	{
		if (!isPartOfUpdate() && containsActor(actor)) {
			actors.remove(actor);
			flagForUpdate();
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * get a list of all the actors currently in this cell
	 * @return a List containing all the actors
	 */
	public List<ModelActor> getAllActors()
	{
		return actors;
	}
	
	/**
	 * check whether a given actor is in this cell
	 * @param actor the actor to be checked
	 * @return true if the given actor is in this cell
	 */
	public boolean containsActor(ModelActor actor)
	{
		for (ModelActor a : actors) {
			if (actor.equals(a)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * @return the number of actors currently in this cell
	 */
	public int noOfActors()
	{
		return actors.size();
	}
	
	/**
	 * @return the latest update, null if no update needed
	 */
	@Override
	public TokenCell grabUpdate()
	{
		if (hasBeenUpdated()) {
			resetUpdate();
			return new TokenCell(true, actors);
		} else {
			return null;
		}
	}
	
	/**
	 * Apply an updated TokenCell to this one
	 * @param updateCell the cell to update this one with
	 * @throws IllegalArgumentException if the update is not of the same type as this one
	 */
	@Override
	public void applyUpdate(ModelCell updateCell)
		throws IllegalArgumentException
	{
		if (updateCell != null) {
			if (!(updateCell instanceof TokenCell)) {
				throw new IllegalArgumentException("Update passed to " + toString() + " was not a  TokenCell");
			}
				
			TokenCell update = (TokenCell) updateCell;
			updateActors(update.getAllActors());
		}
	}
	
	/**
	 * update the actors
	 * @param updateActors the actors list to sync with this cell's
	 */
	private void updateActors(List<ModelActor> updateActors)
	{
		Iterator<ModelActor> actIt = actors.iterator();
		while (actIt.hasNext()) {
			ModelActor a = actIt.next();
			if (!updateActors.contains(a)) {
				actIt.remove();
			}
		}
		Iterator<ModelActor> updIt = updateActors.iterator();
		while (updIt.hasNext()) {
			ModelActor u = updIt.next();
			if (!actors.contains(u)) {
				addActor(u);
			}
		}
		
		
	}
}
